package com

import com.boge.utils.SystemUtils
import java.nio.file.Path
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.zip.ZipInputStream
import kotlin.io.path.*

object Utils {


    fun onWindow(): Boolean {
        return System.getProperty("os.name").startsWith("Windows", true)
    }

    /**
     * 程序临时目录专用
     */
    val tempPath by lazy {
        Path(SystemUtils.tempDir, "FileWatch").also {
            it.createDirectories()
        }
    }

    val executors: ExecutorService by lazy {
        Executors.newThreadPerTaskExecutor(
            Thread.ofVirtual()
                .name("virtual-", 0)
                .factory()
        )
    }

    /**
     * 配置文件路径
     */
    fun configPath(): Path? {
        var config = System.getenv("FILE_WATCH_PATH")
        var configPath: Path? = null
        if (config == null || Path(config).also {
                configPath = it
            }.notExists()) {
            config = System.getProperty("FILE_WATCH_PATH")
            if (config == null || Path(config).also {
                    configPath = it
                }.notExists()) {
                // 尝试从用户目录加载配置，若不存在则从应用运行路径加载
                config = "${System.getProperty("user.home")}/FileWatch/data.json"
                if (Path(config).also {
                        configPath = it
                    }.notExists()) {
                    configPath = SystemUtils.runPath.resolve("data.json")
                }
            }
        }
        return configPath
    }

    /**
     * 使用实验性Path API创建一个快捷方式启动脚本。
     * 该函数从资源中读取一个Windows批处理文件（用于启动操作），将其中的占位符替换为实际路径和文件名，
     * 然后将替换后的脚本写入当前目录下的run.bat文件，并执行该文件。
     *
     * @param source 指定快捷方式指向的源文件路径。
     */
    @OptIn(ExperimentalPathApi::class)
    fun createShortcutStartup(source: Path) {
        // 尝试从资源中读取启动脚本模板
        val inputStream = Main::class.java.getResourceAsStream("/win/FileWatchStartup.bat")
        if (inputStream != null) {
            // 读取模板内容，并替换其中的占位符
            var content = inputStream.readAllBytes().decodeToString()
            content = content.replace("{0}", source.pathString)
            content = content.replace("{1}", source.nameWithoutExtension)

            // 将替换后的内容写入run.bat文件，并在控制台中执行该文件
            Path("./run.bat").also {
                it.writeText(content)
                Runtime.getRuntime().exec(arrayOf("cmd", "/c", it.pathString)).waitFor()
            }.deleteRecursively() // 执行完成后删除run.bat文件
        }
    }

    /**
     * 解压缩ZIP文件。
     *
     * @param inputPath 要解压的ZIP文件的路径。
     * @param outputPath 解压后文件输出的根目录路径。
     * @param folderName 只解压指定的文件。
     */
    fun unZip(inputPath: Path, outputPath: Path, folderName: String? = null) {
        inputPath.normalize()
        outputPath.normalize()

        if (outputPath.isDirectory())
            outputPath.createDirectories()
        else outputPath.createParentDirectories()

        // 打开输入流，准备读取ZIP文件
        val zipInputStream = ZipInputStream(inputPath.inputStream())
        val buffer = ByteArray(1024)
        // 遍历ZIP文件中的所有条目
        var entry = zipInputStream.nextEntry
        var isPass: Boolean
        while (entry != null) {
            val currentEntry = entry
            isPass = folderName.isNotNull { currentEntry.name.startsWith(this) } ?: true
            if (isPass) {
                val fileName = folderName.isNotNull {
                    currentEntry.name.removePrefix(this).removePrefix("/")
                } ?: currentEntry.name
                val file = outputPath.resolve(fileName)
                // 如果条目是目录，则创建目录
                if (currentEntry.isDirectory) {
                    file.createDirectories()
                } else {
                    // 如果条目是文件，则解压文件
                    val currentOutputStream = file.outputStream()
                    // 读取并写入文件数据
                    var bytesRead = zipInputStream.read(buffer)
                    while (bytesRead > 0) {
                        currentOutputStream.write(buffer, 0, bytesRead)
                        bytesRead = zipInputStream.read(buffer)
                    }
                    // 关闭当前文件的输出流
                    currentOutputStream.close()
                }
            }
            // 移动到ZIP文件的下一个条目
            entry = zipInputStream.nextEntry
        }
        // 关闭ZIP文件输入流和输出流
        zipInputStream.close()
    }

}